虽然USM基于指针，但不是所有指针都相同。USM定义了三种不同的分配类型，每种都有单独的方式。设备可能不支持所有类型的USM(甚至不支持)，后面我们会去了解到如何查询设备支持的USM类型。先来了解一下这三种类型的分配和特征，如图6-1所示。\par

\hspace*{\fill} \par %插入空行
图6-1 USM分配方式
\begin{table}[H]
	\begin{tabular}{|l|l|l|l|l|}
		\hline
		类型   & 描述                                & 主机端可访问? & 设备端可访问? & 位于                          \\ \hline
		device & 在设备内存上进行分配              & \XSolidBrush                   & \Checkmark                      & 设备                              \\ \hline
		host   & 在主机内存上进行分配                 & \Checkmark                   & \Checkmark                     & 主机端                                \\ \hline
		shared & 可在主机端和设备端共享 & \Checkmark                    & \Checkmark                     & 可以在主机和设备之间迁移 \\ \hline
	\end{tabular}
\end{table}

\hspace*{\fill} \par %插入空行
\textbf{设备端内存}

这种类型的分配可以拥有指向设备内存(如(G)DDR或HBM)的指针。设备内存可以由运行在设备上的内核函数读取或写入，但是不能从主机直接访问。尝试直接访问设备端内存，可能导致数据不正确或程序崩溃。必须显式使用USM的memcpy机制在主机和设备之间复制数据，对两个位置上的数据进行复制，本章后面会对此继续讨论。\par

\hspace*{\fill} \par %插入空行
\textbf{主机端内存}

第二种类型更容易使用，不需要在主机和设备之间复制数据。在主机和设备上都可以访问主机内存，虽然在设备上可以访问，但不能迁移到设备端内存。对该内存进行读写的内核通常通过较慢的总线(如PCI-Express)进行远程操作，所以必须对编程复杂性和性能进行权衡。尽管主机端的内存可能导致很高的访问成本，但也有使用的场景，比如：很少访问的数据或存在设备内存中无法容纳的大型数据集。\par

\hspace*{\fill} \par %插入空行
\textbf{共享内存}

最后一种类型的内存分配结合了设备和主机内存的属性，结合了主机内存对编程复杂性的便利和设备分配提供的更好的性能，共享内存可以在主机和设备上访问。区别是共享内存可以自动地在主机内存和设备内存之间迁移，无需显式干预。如果数据已经迁移到该设备，那么在该设备上执行的内核访问该段数据，会比从主机远程访问该数据有更好的性能。不过，也有缺点。\par

自动迁移可以通过多种方式实现。不管运行时选择哪种方式来实现共享内存，通常都要付出延迟增加的代价。通过设备内存，可以确切地知道需要复制多少内存，并可以尽可能快地安排数据的复制。自动迁移机制无法对未来进行预见，某些情况下，直到内核尝试访问数据时才开始移动数据，导致内核必须等待或阻塞，直到数据移动完成。其他情况下，运行时很可能不知道内核函数将访问多少数据，可能移动更多的数据，这也会增加内核的延迟。\par

虽然共享分配可以迁移，但并不一定DPC++的所有实现都会迁移。我们希望大多数实现都通过迁移实现共享，但有些设备可能希望实现与主机内存相同。这样的实现中，分配的内存在主机和设备上仍然可见，但是可能无法感知迁移带来的性能提升。\par






































